﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CubePuzzle
{
    public class MatrixBuilder
    {
        private int[][][] matrix;
        private Item [] items;
        private int n;
        private int k;

        public int K
        {
            set
            {
                k = value;
            }

            get
            {
                return k;
            }
        }

        public int N
        {
            set
            {
                n = value;
            }

            get
            {
                return n;
            }
        }

        public Item [] Items
        {
            set
            {
                items = value;
            }

            get
            {
                return items;
            }
        }

        public int[][][] Matrix
        {
            set
            {
                matrix = value;
            }

            get
            {
                return matrix;
            }
        }
        
        public MatrixBuilder(Item[] items, int n, int k)
        {
            this.n = n;
            this.k = k;
            this.items = items;
            matrix = new int[n*k][][];
            for (int i=0; i<n*k; i++)
                matrix[i] = new int[n*k][];

            for (int i=0; i<n*k; i++)
                for (int j=0; j<n*k; j++)
                    matrix[i][j] = new int[n*k];
        }

        public void buildMatrix()
        {
            int bx = n;
            int by = n;
            int bz = n;

            for (int i = 0; i < k; i++)
            {
                for (int ii = bx; ii < bx+n; ii++)
                {
                    for (int jj = by; jj < by+n; jj++)
                    {
                        for (int kk = bz; kk < bz+n; kk++)
                        {
                            matrix[ii][jj][kk] = items[i].getItem(ii-bx,jj-by,kk-bz);
                        }
                    }
                }
                items[i].setX(bx);
                items[i].setY(by);
                items[i].setZ(bz);

                if ((k * n) / bx > 3) bx += (2 * n);
                else
                {
                    bx = n;
                    if ((k * n) / by > 3) by += (2 * n);
                    else
                    {
                        by = n;
                        bz += (2 * n);
                    }
                } 
            }
        }

        public Boolean rotate(int axis, int index)
        {
            int posX = items[index].getX();
            int posY = items[index].getY();
            int posZ = items[index].getZ();

            switch (axis)
            {
                case 1 :
                    for (int i = posX; i < posX + n; i++)
                    {
                        for (int j = posY; j < posY + n; j++)
                        {
                            for (int kk = posZ; kk < posZ + n; kk++)
                            {
                                if ((matrix[i][j][kk] != index + 1) && (matrix[i][j][kk] != 0)) return false;
                            }
                        }
                    }


                    int [][][] temp = new int[n][][];
                    for (int i = 0; i < n; i++)
                        temp[i] = new int[n][];

                    for (int i = 0; i < n; i++)
                        for (int j = 0; j < n; j++)
                            temp[i][j] = new int[n];

                    for (int i = 0; i < n; i++)
                    {
                        for (int j = 0; j < n; j++)
                        {
                            for (int kk = 0; kk < n; kk++)
                            {
                                temp[i][j][kk] = matrix[posX + n - 1 - kk][posY + j][posZ + i];
                            }
                        }
                    }

                    for (int i = posX; i < posX + n; i++)
                    {
                        for (int j = posY; j < posY + n; j++)
                        {
                            for (int kk = posZ; kk < posZ + n; kk++)
                            {
                                matrix[i][j][kk] = temp[i - posX][j - posY][kk - posZ];
                            }
                        }
                    }
                    return true;
                case 2:
                    for (int i = posX; i < posX + n; i++)
                    {
                        for (int j = posY; j < posY + n; j++)
                        {
                            for (int kk = posZ; kk < posZ + n; kk++)
                            {
                                if ((matrix[i][j][kk] != index + 1) && (matrix[i][j][kk] != 0)) return false;
                            }
                        }
                    }


                    temp = new int[n][][];
                    for (int i = 0; i < n; i++)
                        temp[i] = new int[n][];

                    for (int i = 0; i < n; i++)
                        for (int j = 0; j < n; j++)
                            temp[i][j] = new int[n];

                    for (int i = 0; i < n; i++)
                    {
                        for (int j = 0; j < n; j++)
                        {
                            for (int kk = 0; kk < n; kk++)
                            {
                                temp[i][j][kk] = matrix[posX + i][posY + n - 1 - kk][posZ + j];
                            }
                        }
                    }

                    for (int i = posX; i < posX + n; i++)
                    {
                        for (int j = posY; j < posY + n; j++)
                        {
                            for (int kk = posZ; kk < posZ + n; kk++)
                            {
                                matrix[i][j][kk] = temp[i - posX][j - posY][kk - posZ];
                            }
                        }
                    }
                    return true;
                case 3: 
                    for (int i = posX; i < posX + n; i++)
                    {
                        for (int j = posY; j < posY + n; j++)
                        {
                            for (int kk = posZ; kk < posZ + n; kk++)
                            {
                                if ((matrix[i][j][kk] != index + 1) && (matrix[i][j][kk] != 0)) return false;
                            }
                        }
                    }


                    temp = new int[n][][];
                    for (int i = 0; i < n; i++)
                        temp[i] = new int[n][];

                    for (int i = 0; i < n; i++)
                        for (int j = 0; j < n; j++)
                            temp[i][j] = new int[n];

                    for (int i = 0; i < n; i++)
                    {
                        for (int j = 0; j < n; j++)
                        {
                            for (int kk = 0; kk < n; kk++)
                            {
                                temp[i][j][kk] = matrix[posX + n - 1 - j][posY + i][posZ + kk];
                            }
                        }
                    }

                    for (int i = posX; i < posX + n; i++)
                    {
                        for (int j = posY; j < posY + n; j++)
                        {
                            for (int kk = posZ; kk < posZ + n; kk++)
                            {
                                matrix[i][j][kk] = temp[i - posX][j - posY][kk - posZ];
                            }
                        }
                    }
                    return true;

                default: return false;
            }
        }

        public Boolean move(int axis, int index)
        {

            int posX = items[index].getX();
            int posY = items[index].getY();
            int posZ = items[index].getZ();

            switch(axis) 
            {
                case 1: if (posX + n < n * k - 1)
                    {
                        for (int i = posX + n - 1; i > posX-1; i--)
                        {
                            for (int j = posY; j < posY + n; j++)
                            {
                                for (int kk = posZ; kk < posZ + n; kk++)
                                {
                                    if ((matrix[i + 1][j][kk] != 0) && (matrix[i + 1][j][kk] != index + 1) && (matrix[i][j][kk] == index + 1)) return false;
                                }
                            }
                        }

                        for (int i = posX + n - 1; i > posX - 1; i--)
                        {
                            for (int j = posY; j < posY + n; j++)
                            {
                                for (int kk = posZ; kk < posZ + n; kk++)
                                {
                                    if (((matrix[i][j][kk] == index + 1) || (matrix[i][j][kk] == 0)) &&
                                        ((matrix[i + 1][j][kk] == index + 1) || (matrix[i + 1][j][kk] == 0)))
                                    {
                                        matrix[i + 1][j][kk] = matrix[i][j][kk];
                                    }

                                    if ((matrix[i][j][kk] == index + 1) || (matrix[i][j][kk] == 0))
                                        matrix[i][j][kk] = 0;
                                }
                            }
                        }    

                        items[index].setX(posX + 1);
                        return true;
                    }
                    return false;

                case -1: if (posX > 0)
                    {
                        for (int i = posX; i < posX + n; i++)
                        {
                            for (int j = posY; j < posY + n; j++)
                            {
                                for (int kk = posZ; kk < posZ + n; kk++)
                                {
                                    if ((matrix[i - 1][j][kk] != 0) && (matrix[i - 1][j][kk] != index + 1) && (matrix[i][j][kk] == index + 1)) return false;
                                }
                            }
                        }

                        for (int i = posX; i < posX + n; i++)
                        {
                            for (int j = posY; j < posY + n; j++)
                            {
                                for (int kk = posZ; kk < posZ + n; kk++)
                                {
                                    if ((((matrix[i][j][kk] == index + 1) || matrix[i][j][kk] == 0)) && 
                                        (((matrix[i - 1][j][kk] == index + 1) || matrix[i - 1][j][kk] == 0))) 
                                        
                                        matrix[i - 1][j][kk] = matrix[i][j][kk];


                                    if ((matrix[i][j][kk] == index + 1) || (matrix[i][j][kk] == 0))
                                        matrix[i][j][kk] = 0;
                                }
                            }
                        }

                        items[index].setX(posX - 1);
                        return true;
                    }
                    return false;

                case 2: if (posY + n < n * k - 1)
                    {
                        for (int i = posY + n - 1; i > posY - 1; i--)
                        {
                            for (int j = posX; j < posX + n; j++)
                            {
                                for (int kk = posZ; kk < posZ + n; kk++)
                                {
                                    if ((matrix[j][i+1][kk] != 0) && (matrix[j][i+1][kk] != index + 1) && (matrix[j][i][kk] == index + 1)) return false;
                                }
                            }
                        }

                        for (int i = posY + n - 1; i > posY - 1; i--)
                        {
                            for (int j = posX; j < posX + n; j++)
                            {
                                for (int kk = posZ; kk < posZ + n; kk++)
                                {
                                    if (((matrix[j][i][kk] == index + 1) || (matrix[j][i][kk] == 0)) &&
                                        ((matrix[j][i+1][kk] == index + 1) || (matrix[j][i+1][kk] == 0)))
                                    {
                                        matrix[j][i+1][kk] = matrix[j][i][kk];
                                    }

                                    if ((matrix[j][i][kk] == index + 1) || (matrix[j][i][kk] == 0))
                                        matrix[j][i][kk] = 0;
                                }
                            }
                        }

                        items[index].setY(posY + 1);
                        return true;
                    }
                    return false;

                case -2: if (posY > 0)
                    {
                        for (int i = posY; i < posY + n; i++)
                        {
                            for (int j = posX; j < posX + n; j++)
                            {
                                for (int kk = posZ; kk < posZ + n; kk++)
                                {
                                    if ((matrix[j][i-1][kk] != 0) && (matrix[j][i-1][kk] != index + 1) && (matrix[j][i][kk] == index + 1)) return false;
                                }
                            }
                        }

                        for (int i = posY; i < posY + n; i++)
                        {
                            for (int j = posX; j < posX + n; j++)
                            {
                                for (int kk = posZ; kk < posZ + n; kk++)
                                {
                                    if ((((matrix[j][i][kk] == index + 1) || matrix[j][i][kk] == 0)) &&
                                        (((matrix[j][i - 1][kk] == index + 1) || matrix[j][i - 1][kk] == 0)))

                                        matrix[j][i - 1][kk] = matrix[j][i][kk];


                                    if ((matrix[j][i][kk] == index + 1) || (matrix[j][i][kk] == 0))
                                        matrix[j][i][kk] = 0;
                                }
                            }
                        }

                        items[index].setY(posY - 1);
                        return true;
                    }
                    return false;
                case 3: if (posZ + n < n * k - 1)
                    {
                        for (int i = posZ + n - 1; i > posZ - 1; i--)
                        {
                            for (int j = posY; j < posY + n; j++)
                            {
                                for (int kk = posX; kk < posX + n; kk++)
                                {
                                    if ((matrix[kk][j][i + 1] != 0) && (matrix[kk][j][i + 1] != index + 1) && (matrix[kk][j][i] == index + 1)) return false;
                                }
                            }
                        }

                        for (int i = posZ + n - 1; i > posZ - 1; i--)
                        {
                            for (int j = posY; j < posY + n; j++)
                            {
                                for (int kk = posX; kk < posX + n; kk++)
                                {
                                    if (((matrix[kk][j][i] == index + 1) || (matrix[kk][j][i] == 0)) &&
                                        ((matrix[kk][j][i + 1] == index + 1) || (matrix[kk][j][i + 1] == 0)))
                                    {
                                        matrix[kk][j][i + 1] = matrix[kk][j][i];
                                    }

                                    if ((matrix[kk][j][i] == index + 1) || (matrix[kk][j][i] == 0))
                                        matrix[kk][j][i] = 0;
                                }
                            }
                        }

                        items[index].setZ(posZ + 1);
                        return true;
                    }
                    return false;

                case -3: if (posZ > 0)
                    {
                        for (int i = posZ; i < posZ + n; i++)
                        {
                            for (int j = posY; j < posY + n; j++)
                            {
                                for (int kk = posX; kk < posX + n; kk++)
                                {
                                    if ((matrix[kk][j][i - 1] != 0) && (matrix[kk][j][i - 1] != index + 1) && (matrix[kk][j][i] == index + 1)) return false;
                                }
                            }
                        }

                        for (int i = posZ; i < posZ + n; i++)
                        {
                            for (int j = posY; j < posY + n; j++)
                            {
                                for (int kk = posX; kk < posX + n; kk++)
                                {
                                    if ((((matrix[kk][j][i] == index + 1) || matrix[kk][j][i] == 0)) &&
                                        (((matrix[kk][j][i - 1] == index + 1) || matrix[kk][j][i - 1] == 0)))

                                        matrix[kk][j][i - 1] = matrix[kk][j][i];


                                    if ((matrix[kk][j][i] == index + 1) || (matrix[kk][j][i] == 0))
                                        matrix[kk][j][i] = 0;
                                }
                            }
                        }

                        items[index].setZ(items[index].getZ() - 1);
                        return true;
                    }
                    return false;
                default:
                    return false;

            }
        }

    }
}
